package com.example.bluetoothdemo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import com.example.bluetoothdemo.util.BluetoothChatUtil;
import com.example.bluetoothdemo.util.MyUtils;

import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Set;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    /**
     * 蓝牙适配器BluetoothAdapter
     */
    private BluetoothAdapter bluetoothAdapter;
    /**
     * 存放未配对的蓝牙设备
     */
    ArrayList<BluetoothDevice> devicesUnpaired = new ArrayList<>();
    /**
     * 存放未配对的蓝牙设备的名称或地址【方便ListView中展示】
     */
    ArrayList<String> nameUnpaired = new ArrayList<>();
    /**
     * 存放已配对的蓝牙设备 (这个点击获取已配对设备按钮才数据)
     */
    ArrayList<BluetoothDevice> devicesPaired = new ArrayList<>();

    /**
     * 管理蓝牙连接的工具类对象
     */
    private BluetoothChatUtil bluetoothChatUtil;

    /**
     * 用于接收蓝牙查询到的设备的广播
     * BroadcastReceiver 广播接收者
     * BluetoothDevice 蓝牙设备
     */
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            BluetoothDevice device;
            switch (action) {
                case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
                    Log.i(TAG, "ACTION_DISCOVERY_FINISHED: 搜索完毕");
                    MyUtils.simpleToast(MainActivity.this, "蓝牙设备搜索完毕");
                    break;
                case BluetoothDevice.ACTION_FOUND:
                    Log.i(TAG, "ACTION_FOUND: 正在搜索设备...");
                    //搜索到的蓝牙设备【未配对+已配对】
                    device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    try {
                        //取得未配对设备集合
                        if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                            //未配对蓝牙设备List
                            devicesUnpaired.add(device);
                            //未配对蓝牙设备名称List(用于展示在界面上)
                            nameUnpaired.add(device.getName() == null ? device.getAddress() : device.getName());
                            //listView的adapter的data每次更改都要更新
                            unpairedAdapter.notifyDataSetChanged();
                        }
                        break;
                    } catch (SecurityException e) {
                        Log.e(TAG, "蓝牙连接异常", e);
                    }
                    break;
            }
        }
    };

    /**
     * 接收和处理蓝牙连接工具类中 连接管理线程ConnectedThread 及 其他方法 发送的消息
     * 具体的操作需要根据情况进行修改
     */
    @SuppressLint("HandlerLeak")
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BluetoothChatUtil.STATE_CONNECTED:
                    MyUtils.simpleToast(MainActivity.this, "连接成功");
                    break;
                case BluetoothChatUtil.STATE_CONNECT_FAILURE:
                    MyUtils.simpleToast(MainActivity.this, "连接失败");
                    break;
                case BluetoothChatUtil.STATE_CHANGE:
                    MyUtils.simpleToast(MainActivity.this, "正在连接设备..");
                    break;
                case BluetoothChatUtil.MESSAGE_DISCONNECTED:
                    MyUtils.simpleToast(MainActivity.this, "与设备断开连接");
                    break;
                case BluetoothChatUtil.MESSAGE_READ: {
                    //todo 读和写的逻辑需要根据情况定制
                    byte[] buf = msg.getData().getByteArray(BluetoothChatUtil.READ_MSG);
                    String str = new String(buf, 0, buf.length);
                    Toast.makeText(getApplicationContext(), "读成功" + str, Toast.LENGTH_SHORT).show();
                    break;
                }
                case BluetoothChatUtil.MESSAGE_WRITE: {
                    byte[] buf = (byte[]) msg.obj;
                    String str = new String(buf, 0, buf.length);
                    Toast.makeText(getApplicationContext(), "发送成功" + str, Toast.LENGTH_SHORT).show();
                    break;
                }
                default:
                    break;
            }
        }
    };


    //开启蓝牙检测按钮
    private Button startBluetoothBtn;
    //未匹配蓝牙设备ListView,数据源是nameUnpaired(数据源每次更改都要更新)
    private ListView unpairedList;
    //unpairedList的适配器
    ArrayAdapter<String> unpairedAdapter;

    //显示已配对蓝牙设备按钮
    private Button showBluetoothBtn;
    //已配对蓝牙设备ListView,数据源在点击按钮时获取
    private ListView pairedList;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startBluetoothBtn = findViewById(R.id.startBluetoothBtn);
        showBluetoothBtn = findViewById(R.id.showBluetoothBtn);
        unpairedList = findViewById(R.id.unpairedList);
        pairedList = findViewById(R.id.pairedList);

        bluetoothChatUtil = BluetoothChatUtil.getInstance(this);
        bluetoothChatUtil.registerHandler(mHandler);


        //未配对设备ListView配置Adapter (因为nameUnpaired要等搜索蓝牙时动态添加，注意每次修改都要unpairedAdapter调用notifyDataSetChanged)
        unpairedAdapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, nameUnpaired);
        unpairedList.setAdapter(unpairedAdapter);


        //开启蓝牙搜索未绑定设备
        startBluetoothBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //点击时判断蓝牙
                if (!isSupported()) {
                    MyUtils.simpleToast(MainActivity.this, "不支持蓝牙");
                } else {
                    //判断蓝牙是否打开
                    //需要在 AndroidManifest.xml 中添加android.permission.BLUETOOTH权限
                    if (bluetoothAdapter.isEnabled()) {
                        //已经打开蓝牙，判断设备Android版本是否需要动态申请位置权限，解决无法发现蓝牙设备的问题
                        //  Android6.0搜索周围的蓝牙设备需要位置权限ACCESS_COARSE_LOCATION和ACCESS_FINE_LOCATION 其中的一个，并且将手机的位置服务（定位 GPS）打开
                        //  位置权限是dangerous级权限，除了需要在Manifest里申请之外，还需要在代码中进行动态申请。
                        getLocationPermission();
                        //如果被拒绝且不再询问，提示开启才能使用
                        int permissionCheck = 0;
                        permissionCheck = MainActivity.this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
                        permissionCheck += MainActivity.this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);
                        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
                            MyUtils.simpleToast(MainActivity.this, "未给予位置权限，无法使用");
                        } else {
                            //开启蓝牙模块结束
                            //检测蓝牙设备
                            MyUtils.simpleToast(MainActivity.this, "检测蓝牙设备，请耐心等待");
                            searchDevices();
                            unpairedDevicesList();
                        }
                    } else {
                        bluetoothAdapter.enable();
                        //关闭蓝牙：bluetoothAdapter.disable();
                    }
                }
            }
        });

        //展示配对设备
        showBluetoothBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                pairedDevicesList();
            }
        });

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                bluetoothChatUtil.write("你好".getBytes());
            }
        });
    }


    /**
     * 在当前activity的 onStart() 中注册广播
     */
    @Override
    protected void onStart() {
        super.onStart();
        //创建一个查找蓝牙设备的广播意图
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        // 创建一个结束查找蓝牙设备结束的广播意图
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        //注册一个广播接收者，开启查找蓝牙设备意图后将结果以广播的形式返回
        this.registerReceiver(mReceiver, filter);
    }

    @Override
    protected void onStop() {
        super.onStop();
        //取消注册广播
        this.unregisterReceiver(mReceiver);
    }


    /**
     * 搜索蓝牙设备
     * <p>
     * 搜索未配对的设备
     */
    private void searchDevices() {
        try {
            //判断是否正在搜索
            if (bluetoothAdapter.isDiscovering()) {
                //如果正在搜索则取消搜索后再搜索
                bluetoothAdapter.cancelDiscovery();
            }
            // 开始搜索蓝牙设备,搜索到的蓝牙设备通过广播接收者返回
            boolean startDiscovery = bluetoothAdapter.startDiscovery();
            if (startDiscovery) {
                //开始搜索：
                // 清空之前的记录
                devicesUnpaired.clear();
                nameUnpaired.clear();
                //listView的adapter的data每次更改都要更新
                unpairedAdapter.notifyDataSetChanged();
            }
        } catch (SecurityException e) {
            Log.e(TAG, "蓝牙异常", e);
            MyUtils.simpleToast(MainActivity.this, "蓝牙异常");
        }
    }

    /**
     * 未配对设备ListView的初始化和绑定点击事件(与点击设备进行蓝牙配对)
     */
    private void unpairedDevicesList() {
        unpairedAdapter.notifyDataSetChanged();

        unpairedList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                MyUtils.simpleToast(MainActivity.this, String.valueOf(position));
                try {
                    BluetoothDevice device = devicesUnpaired.get((int) id);
                    // 调用配对的方法，此方法是异步的，系统会触发BluetoothDevice.ACTION_PAIRING_REQUEST的广播
                    // 收到此广播后，设置配对的密码
                    Method createBondMethod = device.getClass().getMethod("createBond");
                    createBondMethod.invoke(device);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }


    /**
     * 判断是否设备是否支持蓝牙
     *
     * @return 是否支持
     */
    private boolean isSupported() {
        //初始化
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            Log.i(TAG, "isSupported: 设备不支持蓝牙");
            return false;
        } else {
            return true;
        }
    }


    /**
     * 同时申请两个位置权限的标识
     */
    private final int ACCESS_LOCATION_CODE = 1;

    /**
     * 申请蓝牙功能需要的位置动态权限 (同时申请了两个位置权限)
     * <p>
     * 解决无法发现蓝牙设备的问题
     * 对于发现新设备这个功能, 还需另外两个权限(Android M 以上版本需要显式获取授权,附授权代码):
     */
    @SuppressLint("WrongConstant")
    private void getLocationPermission() {
        //判断设备是否需要动态申请ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION权限
        //  这两个权限是安卓6.0以后使用蓝牙所需要的位置权限(实际上好像只需要其中一个权限)
        int permissionCheck = 0;
        permissionCheck = this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
        permissionCheck += this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);
        //要动态申请的权限
        String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
        //未获得权限时请求动态授权
        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
            //第二个参数可以是任意整型，请求权限的结果回调函数会传入其作为请求代码requestCode
            this.requestPermissions(permissions, ACCESS_LOCATION_CODE);
        }
    }

    /**
     * 请求动态权限的结果回调函数。每次调用 requestPermissions（string[]，int）申请动态权限时都会调用此方法。
     *
     * @param requestCode  传入的请求代码
     * @param permissions  传入permissions的要求 (申请的权限)
     * @param grantResults 相应权限的授予结果
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            //位置权限
            case ACCESS_LOCATION_CODE:
                if (hasAllPermissionGranted(grantResults)) {
                    Log.i(TAG, "onRequestPermissionsResult: 用户允许权限");
                } else {
                    MyUtils.simpleToast(MainActivity.this, "你拒绝了权限申请");
                    Log.i(TAG, "onRequestPermissionsResult: 拒绝搜索设备权限");
                }
                break;
            //有其他动态权限的申请就往后加case
        }
    }

    /**
     * 判断是否申请的所有权限都授权成功
     *
     * @param grantResults 申请一系列动态权限的所有授权结果
     * @return 成功/失败
     */
    private boolean hasAllPermissionGranted(int[] grantResults) {
        for (int grantResult : grantResults) {
            if (grantResult == PackageManager.PERMISSION_DENIED) {
                return false;
            }
        }
        return true;
    }


    /**
     * ***********************************************************************
     * 下面是蓝牙连接模块
     * ***********************************************************************
     */

    /**
     * 我这的方法是：
     * 取得已经配对的蓝牙设备的 名称或者地址 显示在listView中
     * 且listView的选项设置点击事件，以便进行设备连接
     */
    private void pairedDevicesList() {
        try {
            if (bluetoothAdapter == null) {
                MyUtils.simpleToast(MainActivity.this, "请先点击检测按钮");
                return;
            }
            //获取已配对设备集合
            Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
            //listView需要string类型，所以提取名称或者地址以方便展示
            ArrayList<String> data = new ArrayList<>();
            if (pairedDevices.size() > 0) {
                for (BluetoothDevice device : pairedDevices) {
                    //添加listView展示的设备名称或地址
                    data.add((device.getName() == null) ? device.getAddress() : device.getName());
                    //已配对设备添加到Activity的实例变量中
                    devicesPaired.add(device);
                }
            } else {
                data.add("暂无已配对设备");
            }

            //将已配对的设备添加到listView中
            ArrayAdapter<String> adapter = new ArrayAdapter<>(
                    MainActivity.this, android.R.layout.simple_list_item_activated_1, data);
            pairedList.setAdapter(adapter);
            pairedList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    BluetoothDevice device = devicesPaired.get((int) id);
                    try {
                        if (bluetoothAdapter.isDiscovering()) {
                            //取消搜索
                            bluetoothAdapter.cancelDiscovery();
                        }
                    } catch (SecurityException e) {
                        Log.e(TAG, "蓝牙搜索异常");
                        MyUtils.simpleToast(MainActivity.this, "蓝牙搜索异常");
                    }
                    if (bluetoothChatUtil.getState() == BluetoothChatUtil.STATE_CONNECTED) {
                        Toast.makeText(MainActivity.this, "蓝牙已连接", Toast.LENGTH_SHORT).show();
                    } else {
                        //连接远程设备
                        bluetoothChatUtil.connect(device);
                    }
                }
            });

        } catch (SecurityException e) {
            Log.e(TAG, "蓝牙异常");
            return;
        }
    }

    /**
     * 活动和用户进行交互时调用【服务端 需要，不然连接不上】
     */
    @Override
    protected void onResume() {
        super.onResume();
        if (bluetoothChatUtil != null) {
            if (bluetoothChatUtil.getState() == BluetoothChatUtil.STATE_NONE) {
                // 启动蓝牙监听服务
                bluetoothChatUtil.startListen();
            } else if (bluetoothChatUtil.getState() == BluetoothChatUtil.STATE_CONNECTED) {
                BluetoothDevice device = bluetoothChatUtil.getConnectedDevice();
                try {
                    if (null != device && null != device.getName()) {
                        MyUtils.simpleToast(MainActivity.this, "已成功连接到设备" + device.getName());
                    } else {
                        ;MyUtils.simpleToast(MainActivity.this, "未连接到设备");
                    }
                } catch (SecurityException e) {
                    Log.e(TAG, "蓝牙异常");
                }
            }
        }
    }


}